from datetime import datetime, timedelta
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.utils import get_column_letter
import argparse


class HolidayCalculator:
    """节假日计算器"""

    @staticmethod
    def get_fixed_holidays(year):
        """获取固定日期的节假日"""
        fixed_holidays = [
            # 元旦
            (1, 1),
            # 劳动节
            (5, 1),
            # 国庆节（10月1日-7日）
            (10, 1), (10, 2), (10, 3), (10, 4), (10, 5), (10, 6), (10, 7),
        ]
        return [(year, month, day) for month, day in fixed_holidays]

    @staticmethod
    def get_lunar_holidays(year):
        """获取农历节日（简化版，使用近似公历日期）"""
        # 春节假期（农历正月初一至初七，使用近似公历日期）
        spring_festival_map = {
            2023: [(1, 22), (1, 23), (1, 24), (1, 25), (1, 26), (1, 27), (1, 28)],
            2024: [(2, 10), (2, 11), (2, 12), (2, 13), (2, 14), (2, 15), (2, 16)],
            2025: [(1, 29), (1, 30), (1, 31), (2, 1), (2, 2), (2, 3), (2, 4)],
            2026: [(2, 17), (2, 18), (2, 19), (2, 20), (2, 21), (2, 22), (2, 23)],
        }

        # 清明节（4月4日或5日）
        qingming = (4, 4) if year % 4 == 0 else (4, 5)

        # 端午节（农历五月初五，使用近似公历日期）
        dragon_boat_map = {
            2023: (6, 22),
            2024: (6, 10),
            2025: (5, 31),
            2026: (6, 19),
        }

        # 中秋节（农历八月十五，使用近似公历日期）
        mid_autumn_map = {
            2023: (9, 29),
            2024: (9, 17),
            2025: (10, 6),
            2026: (9, 25),
        }

        lunar_holidays = []

        # 添加春节假期
        if year in spring_festival_map:
            for month, day in spring_festival_map[year]:
                lunar_holidays.append((year, month, day))

        # 添加清明节
        lunar_holidays.append((year, qingming[0], qingming[1]))

        # 添加端午节
        if year in dragon_boat_map:
            month, day = dragon_boat_map[year]
            lunar_holidays.append((year, month, day))

        # 添加中秋节
        if year in mid_autumn_map:
            month, day = mid_autumn_map[year]
            lunar_holidays.append((year, month, day))

        return lunar_holidays


class CalendarStyler:
    """日历样式管理器"""

    def __init__(self):
        self.styles = {
            'weekend': {
                'fill': PatternFill(start_color='90EE90', end_color='90EE90', fill_type='solid'),
                'font': Font(name='微软雅黑', color='006400')
            },
            'holiday': {
                'fill': PatternFill(start_color='87CEEB', end_color='87CEEB', fill_type='solid'),
                'font': Font(name='微软雅黑', color='0000FF', bold=True)
            },
            'normal': {
                'fill': PatternFill(fill_type=None),
                'font': Font(name='微软雅黑', color='000000')
            }
        }

    def apply_style(self, cell, style_type):
        """应用样式到单元格"""
        style = self.styles.get(style_type, self.styles['normal'])
        cell.fill = style['fill']
        cell.font = style['font']
        cell.alignment = Alignment(horizontal='center', vertical='center')


class ExcelCalendarGenerator:
    """Excel日历生成器"""

    def __init__(self, year):
        self.year = year
        self.wb = Workbook()
        self.ws = self.wb.active
        self.ws.title = f"{year}年日历"
        self.styler = CalendarStyler()
        self.holiday_calc = HolidayCalculator()

    def generate_holiday_dates(self):
        """生成所有节假日日期"""
        fixed_holidays = self.holiday_calc.get_fixed_holidays(self.year)
        lunar_holidays = self.holiday_calc.get_lunar_holidays(self.year)

        # 合并所有节假日并去重
        all_holidays = set(fixed_holidays + lunar_holidays)
        return [datetime(year, month, day) for year, month, day in all_holidays]

    def get_date_type(self, date, holiday_dates):
        """判断日期类型"""
        if date in holiday_dates:
            return 'holiday'
        elif date.weekday() >= 5:  # 周末
            return 'weekend'
        else:
            return 'normal'

    def setup_worksheet(self):
        """设置工作表格式"""
        # 设置列宽
        for col in range(1, 367):  # 最多366天
            col_letter = get_column_letter(col)
            self.ws.column_dimensions[col_letter].width = 8

    def generate_calendar(self):
        """生成日历"""
        holiday_dates = self.generate_holiday_dates()
        start_date = datetime(self.year, 1, 1)
        end_date = datetime(self.year, 12, 31)

        self.setup_worksheet()

        # 生成日期行
        current_date = start_date
        col_idx = 1

        while current_date <= end_date:
            cell = self.ws.cell(row=1, column=col_idx, value=current_date.strftime("%m/%d"))

            date_type = self.get_date_type(current_date, holiday_dates)
            self.styler.apply_style(cell, date_type)

            current_date += timedelta(days=1)
            col_idx += 1

    def save(self, filename=None):
        """保存文件"""
        if filename is None:
            filename = f"{self.year}年日历表.xlsx"
        self.wb.save(filename)
        return filename


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="生成带样式的日历Excel文件")
    parser.add_argument("--year", type=int, default=datetime.now().year,
                        help="要生成日历的年份（默认当前年份）")
    parser.add_argument("--output", type=str,
                        help="输出文件名（可选）")

    args = parser.parse_args()

    try:
        generator = ExcelCalendarGenerator(args.year)
        generator.generate_calendar()

        output_file = generator.save(args.output)
        print(f"日历文件已生成: {output_file}")
        print(f"年份: {args.year}")
        print("样式说明:")
        print("- 周末: 绿色背景")
        print("- 节假日: 蓝色背景，加粗字体")
        print("- 正常工作日: 无背景色")

    except Exception as e:
        print(f"生成日历时出错: {e}")


if __name__ == "__main__":
    main()
